#include <istream>
#include <iostream>
#include <fstream>
#include <string.h>

using namespace std;

//C++根据文件内容的数据格式分为二进制文件和文本文件
//采用文件流对象操作文件的一般步骤：
//1.定义一个文件流对象
//ios_base ifile(只输入用)
//ofstream ofile(只输出用)
//fstream iofile(既输入又输出用)
//2.使用文件流对象的成员函数打开一个磁盘文件，使得文件流对象和磁盘文件之间建立联系
//3.使用提取和插入运算符对文件进行读写操作，或使用成员函数进行读写
//4.关闭文件

//使用文件IO流用文本以及二进制方式演示读写配置文件
struct server_info
{
    char _ip[32];
    int _port;
};

struct config_manager
{
public:
    config_manager(const char* config_file = "./qdsserver.config")
        :_config_file(config_file)
        {}

    void write_bin(const server_info& info)
    {
        //这里用二进制的方式打开写
        ofstream ofs(_config_file.c_str(), ios_base::out | ios_base::binary);
        ofs.write((const char*)&info, sizeof(server_info));
        ofs.close();
    }

    void read_bin(server_info& info)
    {
        //这里用二进制方式打开读
        ifstream ifs(_config_file.c_str(), ios_base::in | ios_base::binary);
        ifs.read((char*)&info, sizeof(server_info));
        ifs.close();
    }
    
    void write_text(const server_info& info)
    {
        //这里会发现IO流写整形比C语言那套就简单多了，
        //C语言得先把整形itoa再写
        ofstream ofs(_config_file.c_str());
        //记得设置分隔符'\n' 或者 ' ',不然读取的时候会把整个都读取了
        //我们需要的是分别读取
        ofs << info._ip << endl;
        ofs << info._port << endl;
        ofs.close();
    }

    void read_text(server_info& info)
    {
        //这里会发现IO流读整形比C语言那套就简单多了，
        //C语言得先读字符串，再atoi
        ifstream ifs(_config_file.c_str());
        ifs >> info._ip >> info._port;
        ifs.close();
    }

private:
        string _config_file;
};

class Date
{
    //friend ofstream& operator<<(ofstream& of, Date& d);
    friend ostream& operator<<(ostream& os, const Date& d);
public:
    Date(int year = 2022, int month = 10, int day = 16)
        :_year(year)
         ,_month(month)
         ,_day(day)
    {}
    
protected:
    int _year;
    int _month;
    int _day;
};

//ofstream& operator<<(ofstream& ofs, Date& d)
//{
//   ofs << d._year << " " << d._month << " " << d._day << " "<< endl;
//   return ofs;
//}

ostream& operator<<(ostream& os, const Date& d)
{
   os << d._year << " " << d._month << " " << d._day << " "<< endl;
   return os;
}

int main()
{
   //config_manager cfg_mgr;

   //server_info write_info = {"127.0.0.1", 80};
   //server_info read_info;
    
   //二进制读写
   //cfg_mgr.write_bin(write_info);
   //cfg_mgr.read_bin(read_info);
   //cout << read_info._ip << "." << read_info._port << endl;

   //文本读写
   //cfg_mgr.write_text(write_info);
   //cfg_mgr.read_text(read_info);
   //cout << read_info._ip << "." << read_info._port << endl;

    //这里为什么第一个可以成功,但是第二个不能成功?
    //ofstream是ostream的子类,ofstream里面的内置类型的<<重载
    //调用的是ostream里面的
    //所以第二个运用继承,调用的是ostream的重载函数
    //返回值是ostream的对象,那么就和我们重载的<<匹配不上了
    //第一个优先调用我们的<<重载,返回的是ofstream类型对象
    //可以进行切片后,匹配ostream的重载函数
    //Date d;
    //int a = 10;
    //ofstream ofs("test.txt");
    //ofs << d << a << endl;
    ////ofs << a << endl << d;
    
    //正确的做法应该是重载ostream类型的<<
    //这样的话,就不会存在返回值不同,匹配不上的问题了
    //这里运用了多态的原理
    Date d;
    int a = 10;
    ofstream ofs("test.txt");
    ofs << d << a << endl;
    ofs << a << endl << d;
    return 0;
}
